//===----------------------------------------------------------------------===//
//
//                         CMU-DB Project (15-445/645)
//                         ***DO NO SHARE PUBLICLY***
//
// Identification: src/page/b_plus_tree_leaf_page.cpp
//
// Copyright (c) 2018, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <sstream>

#include "common/exception.h"
#include "common/rid.h"
#include "storage/page/b_plus_tree_leaf_page.h"

namespace bustub {

/*****************************************************************************
 * HELPER METHODS AND UTILITIES
 *****************************************************************************/

/**
 * Init method after creating a new leaf page
 * Including set page type, set current size to zero, set next page id and set max size
 */
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::Init(int max_size) {
  SetPageType(IndexPageType::LEAF_PAGE);
  SetSize(0);
  SetMaxSize(max_size);
  next_page_id_ = INVALID_PAGE_ID;
}

/**
 * Helper methods to set/get next page id
 */
INDEX_TEMPLATE_ARGUMENTS
auto B_PLUS_TREE_LEAF_PAGE_TYPE::GetNextPageId() const -> page_id_t { return next_page_id_; }

INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::SetNextPageId(page_id_t next_page_id) { next_page_id_ = next_page_id; }

/*
 * Helper method to find and return the key associated with input "index"(a.k.a
 * array offset)
 */
INDEX_TEMPLATE_ARGUMENTS
auto B_PLUS_TREE_LEAF_PAGE_TYPE::KeyAt(int index) const -> KeyType {
  // replace with your own code
  return array_[index].first;
}

INDEX_TEMPLATE_ARGUMENTS
auto B_PLUS_TREE_LEAF_PAGE_TYPE::ValueAt(int index) const -> ValueType {
  // replace with your own code
  return array_[index].second;
}

INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::SetKeyAt(int index, const KeyType &key) { array_[index].first = key; }

INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::SetValueAt(int index, const ValueType &value) { array_[index].second = value; }

INDEX_TEMPLATE_ARGUMENTS
auto B_PLUS_TREE_LEAF_PAGE_TYPE::DeleteKeyFromNode(const KeyType &key, KeyComparator cmp) -> bool {
  int index = -1;
  for (int i = 0; i < GetSize(); i++) {
    if (cmp(key, KeyAt(i)) == 0) {
      index = i;
    }
  }
  if (index == -1) {
    return false;
  }
  while (index < GetSize() - 1) {
    SetKeyAt(index, KeyAt(index + 1));
    SetValueAt(index, ValueAt(index + 1));
    index++;
  }
  SetSize(GetSize() - 1);
  return true;
}

INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::CombineWithRightSibling(
    BPlusTreeLeafPage<KeyType, ValueType, KeyComparator> *right_sibling) {
  for (int index = 0; index < right_sibling->GetSize(); index++) {
    SetKeyAt(GetSize() + index, right_sibling->KeyAt(index));
    SetValueAt(GetSize() + index, right_sibling->ValueAt(index));
  }
  SetSize(GetSize() + right_sibling->GetSize());
  right_sibling->SetSize(0);
  SetNextPageId(right_sibling->GetNextPageId());
}

INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::CombineWithLeftSibling(
    BPlusTreeLeafPage<KeyType, ValueType, KeyComparator> *left_sibling) {}

INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::StoleLastElement(BPlusTreeLeafPage<KeyType, ValueType, KeyComparator> *thief) {
  for (int index = thief->GetSize(); index > 0; index--) {
    thief->SetKeyAt(index, thief->KeyAt(index - 1));
    thief->SetValueAt(index, thief->ValueAt(index - 1));
  }
  thief->SetKeyAt(0, KeyAt(GetSize() - 1));
  thief->SetValueAt(0, ValueAt(GetSize() - 1));
  SetSize(GetSize() - 1);
  thief->SetSize(thief->GetSize() + 1);
}

INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::StoleFirstElement(BPlusTreeLeafPage<KeyType, ValueType, KeyComparator> *thief) {
  thief->SetKeyAt(thief->GetSize(), KeyAt(0));
  thief->SetValueAt(thief->GetSize(), ValueAt(0));
  for (int index = 0; index < GetSize() - 1; index++) {
    SetKeyAt(index, KeyAt(index + 1));
    SetValueAt(index, ValueAt(index + 1));
  }
  SetSize(GetSize() - 1);
  thief->SetSize(thief->GetSize() + 1);
}

INDEX_TEMPLATE_ARGUMENTS
auto B_PLUS_TREE_LEAF_PAGE_TYPE::GetLeafMappingType(int index) const -> const MappingType & { return array_[index]; }

template class BPlusTreeLeafPage<GenericKey<4>, RID, GenericComparator<4>>;
template class BPlusTreeLeafPage<GenericKey<8>, RID, GenericComparator<8>>;
template class BPlusTreeLeafPage<GenericKey<16>, RID, GenericComparator<16>>;
template class BPlusTreeLeafPage<GenericKey<32>, RID, GenericComparator<32>>;
template class BPlusTreeLeafPage<GenericKey<64>, RID, GenericComparator<64>>;
}  // namespace bustub
